//
//  SQLite.m
//  OmniVox
//
//  Created by Petr Homola on 02/06/15.
//  Copyright (c) 2015 Petr Homola. All rights reserved.
//

#import "SQLite.h"
#import <sqlite3.h>

@implementation SQLiteDatabase {
    sqlite3* db;
}

- (id)initWithFileName:(NSString*)fileName {
    if ((self = [super init])) {
        int s = sqlite3_open([fileName cStringUsingEncoding: NSUTF8StringEncoding], &db);
        if (s != SQLITE_OK) { return nil; }
    }
    return self;
}

- (id)initWithDocumentFileName:(NSString*)fileName {
    NSURL* documentsDirectory = [[NSFileManager defaultManager] URLsForDirectory: NSDocumentDirectory
                                                                       inDomains: NSUserDomainMask][0];
    NSString* filePath = [[documentsDirectory path] stringByAppendingPathComponent: fileName];
    return [self initWithFileName: filePath];
}

- (void)close {
    if (db != NULL) { printf("closing SQL database\n"); sqlite3_close(db); db = NULL; }
}

- (void)dealloc { [self close]; }

- (void)finalize { [self close]; }

- (BOOL)executeSQL:(NSString*)sql {
    char* err = NULL;
    int s = sqlite3_exec(db, [sql cStringUsingEncoding: NSUTF8StringEncoding], NULL, 0, &err);
    if (s != SQLITE_OK) { printf("SQL error: %s\n", err); return NO; }
    return YES;
}

- (BOOL)executeSQL:(NSString*)sql params:(NSArray*)params {
    sqlite3_stmt* stmt;
    int s = sqlite3_prepare(db, [sql cStringUsingEncoding: NSUTF8StringEncoding], -1, &stmt, NULL);
    if (s != SQLITE_OK) { printf("%s\n", sqlite3_errmsg(db)); return NO; }
    for (int i = 0; i < [params count]; i++) {
        id param = [params objectAtIndex: i];
        if ([param isKindOfClass: [NSString class]]) sqlite3_bind_text(stmt, i + 1, [param cStringUsingEncoding: NSUTF8StringEncoding], -1, SQLITE_STATIC);
        else if ([param isKindOfClass: [NSNumber class]]) sqlite3_bind_double(stmt, i + 1, [param doubleValue]);
        else {
            printf("don't know how to handle %s\n", [[param description] cStringUsingEncoding: NSUTF8StringEncoding]);
            NSLog(@"%@ %@", param, NSStringFromClass([param class]));
        }
    }
    sqlite3_step(stmt);
    int s2 = sqlite3_finalize(stmt);
    if (s2 != SQLITE_OK) printf("%s\n", sqlite3_errmsg(db));
    return s2 == SQLITE_OK;
}

- (NSArray*)querySQL:(NSString*)sql {
    return [self querySQL: sql params: nil];
}

- (NSArray*)querySQL:(NSString*)sql params:(NSArray*)params {
    sqlite3_stmt* stmt;
    int s = sqlite3_prepare(db, [sql cStringUsingEncoding: NSUTF8StringEncoding], -1, &stmt, NULL);
    if (s != SQLITE_OK) { printf("%s\n", sqlite3_errmsg(db)); return nil; }
    for (int i = 0; i < [params count]; i++) {
        id param = [params objectAtIndex: i];
        if ([param isKindOfClass: [NSString class]]) sqlite3_bind_text(stmt, i + 1, [param cString], -1, SQLITE_STATIC);
        else if ([param isKindOfClass: [NSNumber class]]) sqlite3_bind_double(stmt, i + 1, [param doubleValue]);
    }
    NSMutableArray* result = [[NSMutableArray alloc] init];
    while ((s = sqlite3_step(stmt)) == SQLITE_ROW) {
        NSMutableArray* row = [[NSMutableArray alloc] init];
        for (int i = 0; i < sqlite3_column_count(stmt); i++) {
            //const char* columnName = sqlite3_column_name(stmt, i);
            switch (sqlite3_column_type(stmt, i)) {
                case SQLITE_TEXT:
                    [row addObject: [NSString stringWithCString: (const char*)sqlite3_column_text(stmt, i) encoding: NSUTF8StringEncoding]];
                    break;
                case SQLITE_INTEGER:
                    [row addObject: [NSNumber numberWithInt: sqlite3_column_int(stmt, i)]];
                    break;
                case SQLITE_FLOAT:
                    [row addObject: [NSNumber numberWithDouble: sqlite3_column_double(stmt, i)]];
                    break;
                case SQLITE_NULL:
                    [row addObject: [NSNull null]];
                    break;
                default: printf("couldn't handle column %s, unknown type: %d\n", sqlite3_column_name(stmt, i), sqlite3_column_type(stmt, i));
            }
        }
        [result addObject: row];
    }
    sqlite3_finalize(stmt);
    return s == SQLITE_DONE ? result : nil;
    
}

@end
